home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / misc / sci / RARS_Amiga_3.lha / RARS / draw.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-27  |  18.9 KB  |  525 lines

  1. // DRAW.CPP - the system-independent graphics portion of RARS 0.39
  2. // (was GRAPHICS.CPP) - by Mitchell E. Timin, State College, PA
  3. // See GI.H, CAR.H & TRACK.H for class and structure declarations.
  4. // This version is for Borland C++, version 3.1, and is for DOS.
  5. // This is part of version 0.60 of RARS (Robot Auto Racing Simulation).
  6. // GI.CPP is the system-dependent graphics portion of RARS.
  7. // ver. 0.1 release January 12, 1995
  8. // ver. 0.2 1/23/95
  9. // ver. 0.3 2/7/95
  10. // ver. 0.39 3/6/95 
  11. // ver. 0.45 3/21/95
  12. // ver. 0.50 4/5/95
  13. // ver. 0.6b 5/8/95 b for beta
  14.  
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <math.h>
  18. #include "car.h"
  19. #include "track.h"
  20. #include "os.h"
  21.  
  22. static double finish_x, finish_y;         // These four variables are used to
  23. static double finish_y_in, finish_y_out;  // locate the finish line on the screen.
  24. static double spacing;                    // see leaders()
  25. static segment *trackout; // global variables that describe the track:
  26. static segment *trackin;
  27. static     int  NSEG;
  28. static  double  width;
  29.  
  30. extern Car* pcar[];      // array of pointers to the various cars
  31. extern double length; // total lenth of track (smaller of inner and outer rails)
  32. extern car_ID drivers[];   // array of pointers to their name strings
  33. extern double CHR_HGT;   // height in feet of row of text
  34. extern int no_display;   // when set, do no graphics
  35.  
  36. /* add prototypes which should have been there all along */
  37. void draw_arc(double, double, double, double, double);
  38.  
  39. // These six functions are member functions of the Car class.
  40. // All they do is fetch private data from the car objects.
  41. inline double Car::get_speed(void)
  42. {  return sqrt(xdot * xdot + ydot * ydot);  }
  43.  
  44. inline double Car::get_vc(void)
  45. {  return vc;  }
  46.  
  47. inline double Car::get_alpha(void)
  48. {  return alpha;  }
  49.  
  50. inline double Car::get_power(void)
  51. {  return power;  }
  52.  
  53. inline double Car::get_lin_acc(void)
  54. {  return tan_a/g;  }
  55.  
  56. inline double Car::get_lat_acc(void)
  57. {  return cen_a/g;  }
  58.  
  59. int round(double given)  // convert double to int by rounding
  60. {
  61.    if(given > 0.0)
  62.       return int(given + .5);
  63.    else
  64.       return int(given - .5);
  65. }
  66.  
  67. // Convert input into an ASCII string with two decimal digits.
  68. void make_dec_string(char* out,         // pointer to destination string
  69.                      double input)      // value to be converted
  70. {
  71.    long int value;
  72.    char intpart[5], decpart[4];
  73.    int neg = 0;                          // to flag negative numbers      
  74.  
  75.    if(input < 0)  {
  76.       neg = 1;
  77.       input = -input;
  78.    }
  79.  
  80.    value = (long int)(100.0 * input + .5);
  81.    itoa(int(value / 100), intpart, 10);
  82.    itoa(int(value % 100), decpart, 10);
  83.    if(decpart[1] == '\0') {   // we might have to stick in a leading zero:
  84.       decpart[2] = '\0';
  85.       decpart[1] = decpart[0];
  86.       decpart[0] = '0';
  87.    }
  88.    if(neg) {                 // we might have to put a minus sign in front:
  89.       strcpy(out, "-");
  90.       strcat(out, intpart);
  91.    }
  92.    else
  93.       strcpy(out, intpart);
  94.    strcat(out, ".");
  95.    strcat(out, decpart);
  96. }
  97.  
  98. // Assemble a string for the average speed of car i.  (goes to char* out)
  99. void get_avg_spd(int i, char* out)
  100. {
  101.     make_dec_string(out, pcar[i]->speed_avg * MPH_FPS);
  102. }
  103.  
  104. // Assemble a string for the maximum speed of car i.  (goes to char* out)
  105. void get_max_spd(int i, char* out)
  106. {
  107.     make_dec_string(out, pcar[i]->speed_max * MPH_FPS);
  108. }
  109.  
  110. // Draws the path specified by the segment array and starting
  111. // conditions which are given as parameters.  Also, fills in the
  112. // un-initialized portions of the segment array.  Returns the length.
  113. double drawpath(double xstart,      // coordinates of starting point
  114.                 double ystart,
  115.                 double alfstart,    // starting tangent angle
  116.                 segment *track)     // pointer to structure that defines path
  117. {
  118.    double length = 0;          // to accumulate total length of path
  119.    double cenx, ceny;          // center of circle arc
  120.    double radius;              // radius of circle arc (negative == rt. turn)
  121.    double x, y, alf;           // position and direction of start of segment
  122.    double newx, newy, newalf;  // and the one after that  (alf in radians)
  123.    int i;
  124.  
  125.    x = xstart;  y = ystart;   // store starting point & direction
  126.    alf = alfstart;
  127.  
  128.    for(i=0; i < NSEG; i++) {                 // for each segment:
  129.       radius = track[i].radius;
  130.       if(radius == 0.0) {                   // is this a straightaway?
  131.          length += track[i].length;
  132.          newx = x + track[i].length * cos(alf);      // find end coordinates
  133.          newy = y + track[i].length * sin(alf);
  134.          track[i].end_x = newx;   track[i].end_y = newy;    // fill in these
  135.          track[i].beg_x = x;      track[i].beg_y = y;       // empty slots in
  136.          track[i].beg_ang = track[i].end_ang = alf;         // the track array
  137.          newalf = alf;                                // direction won't change
  138.          if(!no_display)
  139.             draw_line(x, y, newx, newy);              // draw the straight line
  140.          if(i == 0)      {      // find pixel locations of start/finish line:
  141.               finish_y = newy;   // assume straightaway parallel to x-axis
  142.               finish_x = x + FINISH * length;
  143.          }
  144.       }
  145.       else if(radius > 0.0) {
  146.          length += radius * track[i].length;
  147.          cenx = x - radius * sin(alf);  // compute center location:
  148.          ceny = y + radius * cos(alf);
  149.          track[i].cen_x = cenx;   track[i].cen_y = ceny;  // fill empty slots
  150.          track[i].beg_ang = alf;
  151.          newalf = alf + track[i].length;           // compute new direction
  152.          if(newalf > 2.0 * PI)
  153.             newalf -= 2.0 * PI;
  154.          track[i].end_ang = newalf;                // fill this empty slot
  155.          newx = cenx + radius * sin(newalf);   // location of end
  156.          newy = ceny - radius * cos(newalf);
  157.          track[i].end_x = newx;   track[i].end_y = newy;  // fill in these
  158.          track[i].beg_x = x;      track[i].beg_y = y;     // empty slots
  159.          if(!no_display)
  160.             draw_arc(radius, cenx, ceny, alf, track[i].length); // draw the arc
  161.       }
  162.       else {
  163.          length -= radius * track[i].length;
  164.          cenx = x - radius * sin(alf);  // compute center location:
  165.          ceny = y + radius * cos(alf);
  166.          track[i].cen_x = cenx;   track[i].cen_y = ceny;  // fill empty slots
  167.          track[i].beg_ang = alf;
  168.          newalf = alf - track[i].length;           // compute new direction
  169.          if(newalf < -2.0 * PI)
  170.             newalf += 2.0 * PI;
  171.          track[i].end_ang = newalf;                // fill this empty slot
  172.          newx = cenx + radius * sin(newalf);   // location of end
  173.          newy = ceny - radius * cos(newalf);
  174.          track[i].end_x = newx;   track[i].end_y = newy;  // fill in these
  175.          track[i].beg_x = x;      track[i].beg_y = y;     // empty slots
  176.          if(!no_display)
  177.             draw_arc(radius, cenx, ceny, alf, track[i].length); // draw the arc
  178.       }
  179.       x = newx;                     // repeat with new position and direction:
  180.       y = newy;
  181.       alf = newalf;
  182.    }
  183.    // To close the circuit, draw a line from the last point back to the first.
  184.    // This usually is not necessary, but it prevents flood fill leaking.
  185.    if (!no_display)
  186.       draw_line(x, y, xstart, ystart);
  187.  
  188.    return length;      // return the length of the path
  189. }
  190.  
  191. // Draw a little car on the screen, at given position and orientation,
  192. // and with the given colors.  (to erase the car, call it with track_color)
  193. void drawcar(double x,         // coordinates of center of car
  194.             double y,
  195.             double ang,       // orientation angle of car, wrt x-axis, radians
  196.             int nose,  // color of front portion
  197.             int tail)  // color of rear portion
  198. {
  199.    double xx, yy, endx, endy;
  200.    double sine, cosine, dx, dy;
  201.    int i;
  202.  
  203.    sine = sin(ang);    cosine = cos(ang);
  204.    xx = x + cosine * CARLEN/2 - sine * CARWID/2;    // left front corner coords
  205.    yy = y + cosine * CARWID/2 + sine * CARLEN/2;
  206.    x = xx;  y = yy;                                 // save the above values
  207.    dx = 0.3333 * CARWID * sine;
  208.    dy = -.3333 * CARWID * cosine;
  209.    // below we draw four parallel lines to form the body of the car:
  210.    set_color(tail);
  211.    for(i=0; i<=3; i++) {
  212.       endx = xx - CARLEN * cosine;
  213.       endy = yy - CARLEN * sine;
  214.       draw_line(xx, yy, endx, endy);
  215.       if(i == 3) break;
  216.       xx += dx;
  217.       yy += dy;
  218.    }
  219.    // now four short lines of the nose color to decorate the front:
  220.    set_color(nose);
  221.    xx = x;  yy = y;             // restore x and y to left front of car
  222.    for(i=0; i<=3; i++) {
  223.       endx = xx + CARWID * sine;
  224.       endy = yy - CARWID * cosine;
  225.       draw_line(xx, yy, endx, endy);
  226.       if(i == 3) break;
  227.       xx += dy;
  228.       yy -= dx;
  229.    }
  230. }
  231.  
  232. void lapper(int which, int lap)  // shows lap count on scoreboard,
  233. {                                // also returns lap+1 to advance the lap count
  234.    char string[] = "     ";   
  235.  
  236.    if(lap < 0)
  237.       lap = 0;
  238.  
  239.    set_fill_color(FIELD_COLOR);   // the green part is off the track
  240.    // This bar erases the previous lap count:
  241.    rectangle(SCORE_BOARD_X + 10*CHR_WID,
  242.              SCORE_BOARD_Y - which*CHR_HGT,
  243.              SCORE_BOARD_X + 13*CHR_WID,
  244.              SCORE_BOARD_Y - (which+.9)*CHR_HGT);
  245.  
  246.    set_color(TEXT_COLOR);          // now print text in black:
  247.    itoa(lap, string, 10);
  248.    text_output(SCORE_BOARD_X + 10 * CHR_WID,
  249.                SCORE_BOARD_Y - which * CHR_HGT, string);
  250. }
  251.  
  252. void designate(int i)      // marks car i on scoreboard, with a ">"
  253. {
  254.    static int iwas = -1;    // the previous i, for erasing
  255.  
  256.    set_fill_color(FIELD_COLOR);
  257.    // This small rectangle erases the previous designator:
  258.    if(iwas >= 0)
  259.      rectangle(SCORE_BOARD_X - .7 * CARLEN - CHR_WID,
  260.                SCORE_BOARD_Y - iwas * CHR_HGT,
  261.                SCORE_BOARD_X - .7 * CARLEN -.2 * CHR_WID,
  262.                SCORE_BOARD_Y - (iwas + .9) * CHR_HGT);
  263.  
  264.    // now print the new designator
  265.    if(i >= 0)  {
  266.       set_color(TEXT_COLOR);
  267.       text_output(SCORE_BOARD_X - .7 * CARLEN - CHR_WID,
  268.                SCORE_BOARD_Y - i * CHR_HGT, ">");
  269.    }
  270.    else if(iwas > -1) {     // if no robot is designated, then erase the IP
  271.       rectangle(IP_X, IP_Y, IP_X + 21 * CHR_WID, IP_Y - CHR_HGT); // erase name
  272.       rectangle(IP_X,                IP_Y - CHR_HGT,         // erase data
  273.                 IP_X + 17.5 * CHR_WID, IP_Y - 7 * CHR_HGT);
  274.    }
  275.  
  276.    iwas = i;
  277. }
  278.  
  279. void border(void)   // draws a thin border around the entire screen
  280. {
  281.    set_color(RAIL_COLOR);
  282.    draw_line(0.0, 0.0, X_MAX, 0.0);
  283.    draw_line(X_MAX, 0.0, X_MAX, Y_MAX);
  284.    draw_line(X_MAX, Y_MAX, 0.0, Y_MAX);
  285.    draw_line(0.0, Y_MAX, 0.0, 0.0);
  286. }
  287.  
  288. // Initializes graphics system, draws track, fills in colored regions:
  289. void graph_setup(void)
  290. {
  291.    double alt_len;         // used in deciding the length of the track
  292.  
  293.    build_track();  // read track data and fill in trackout[], trackin[]
  294.  
  295.    // get track information into our file scope global variables:
  296.    NSEG = get_track_description().NSEG;
  297.    width = get_track_description().width;
  298.    trackin = get_track_description().trackin;
  299.    trackout = get_track_description().trackout;
  300.  
  301.    if(!no_display)  {
  302.       initialize_graphics();
  303.       // paint the whole screen green:
  304.       set_fill_color(FIELD_COLOR);
  305.       rectangle(0.0, Y_MAX, X_MAX, 0.0);
  306.       border();               // draw border at screen boundary
  307.    }
  308.  
  309.    // draw outer track boundary:
  310.    length = drawpath(TRK_STRT_X, TRK_STRT_Y, 0, trackout);
  311.    finish_y_out = finish_y;                   // locate one end of finish line
  312.    // draw inner track boundary:
  313.    alt_len = drawpath(TRK_STRT_X, TRK_STRT_Y+width, 0, trackin);
  314.    if(alt_len < length)     // take length of shorter rail as track length
  315.       length = alt_len;
  316.    finish_y_in = finish_y;        // locate other end of finish line
  317.    if(no_display)
  318.       return;
  319.    // pave the track:
  320.    set_fill_color(TRACK_COLOR);
  321.    flood_fill(TRK_STRT_X, TRK_STRT_Y + width/2);     // color the track
  322. }
  323.  
  324. void refresh_finish_line()   // re-draw the finish line:
  325. {
  326.    set_color(TEXT_COLOR);
  327.    draw_line(finish_x, finish_y_out, finish_x, finish_y_in);
  328. }
  329.  
  330. // Put up the scoreboard:
  331. void scoreboard(STAGE stage)
  332. {
  333.    int i;
  334.  
  335.    double XS = SCORE_BOARD_X;
  336.    double YS = SCORE_BOARD_Y;
  337.    char string[] = "0123456789ABCD";
  338.    int kount;
  339.  
  340.    spacing = 1.15 * CHR_HGT;   // for the leader board only
  341.    // these rectangles are for the leader board car pictures:
  342.    kount = car_count < 5 ? car_count : 5;
  343.    // first erase the old board, if any:
  344.    set_fill_color(FIELD_COLOR);
  345.    rectangle(LDR_BRD_X - 1.9 * CARLEN, LDR_BRD_Y - CHR_HGT,
  346.              LDR_BRD_X + 19*CHR_WID, LDR_BRD_Y - (kount + .7) * spacing);
  347.    set_fill_color(TRACK_COLOR);   // rectangular background for car pictures:
  348.    rectangle(LDR_BRD_X - 1.9 * CARLEN, LDR_BRD_Y - CHR_HGT,
  349.              LDR_BRD_X -.5 * CARLEN, LDR_BRD_Y - (kount + .7) * spacing);
  350.    // these rectangles are for the scoreboard car pictures:
  351.    // first erase the old board, if any:
  352.    set_fill_color(FIELD_COLOR);
  353.    rectangle(XS-.7*CARLEN, YS+CHR_HGT/2, XS+13*CHR_WID,
  354.                                YS - car_count * CHR_HGT);
  355.    set_fill_color(TRACK_COLOR);
  356.    rectangle(XS-.7*CARLEN, YS+CHR_HGT/2, XS+.5*CARLEN,
  357.                                YS - car_count * CHR_HGT);
  358.    // draw the cars on the scoreboard:
  359.    for(i=0; i<car_count; i++) {
  360.       drawcar(XS-.1*CARLEN, YS - i * CHR_HGT - CARWID/2, 0,
  361.                      drivers[i].paint_job.nose, drivers[i].paint_job.tail);
  362.       set_color(TEXT_COLOR);
  363.       itoa(lap_count, string, 10);
  364.       text_output(XS+2*CHR_WID, YS - i * CHR_HGT, drivers[i].rob_name);
  365.       (void)lapper(i,-1);
  366.    }
  367.    // erase either "Practice" or "Race Length", and number of laps:
  368.    rectangle(XS - 13 * CHR_WID, SCORE_BOARD_Y + 1.5 * CHR_HGT,
  369.               XS - 3 * CHR_WID, SCORE_BOARD_Y - 1.5 * CHR_HGT);
  370.    text_output(XS - 13 * CHR_WID, SCORE_BOARD_Y + 1.5 * CHR_HGT,
  371.       stage == PRACTICE ? "  Practice   Car  Driver  Laps"
  372.                         : "Race Length  Car  Driver  Laps");
  373.    text_output(LOTIX, LOTIY, "track length      mi.");
  374.    make_dec_string(string, length/5280.0);
  375.    text_output(LOTIX + 11.5 * CHR_WID, LOTIY, string);
  376.    // Show the name of the track:
  377.    text_output(LOTIX, LOTIY + CHR_HGT, "track is");
  378.    for(i=0; trackfile[i]; i++)
  379.       if(trackfile[i] == '.' || trackfile[i] == 0)
  380.          break;
  381.       else
  382.          string[i] = trackfile[i];
  383.    string[i] = 0;
  384.    text_output(LOTIX + 8 * CHR_WID, LOTIY + CHR_HGT, string);
  385.  
  386.    itoa(stage == PRACTICE ? practice : lap_count, string, 10);
  387.    text_output(SCORE_BOARD_X-10*CHR_WID, SCORE_BOARD_Y, string);
  388.    text_output(SCORE_BOARD_X-7*CHR_WID, SCORE_BOARD_Y, "laps");
  389.    text_output(LDR_BRD_X - CHR_WID, LDR_BRD_Y, "LEADERS:   max   avg");
  390.    text_output(LDR_BRD_X+11.5*CHR_WID, LDR_BRD_Y+CHR_HGT, "mph");
  391. }
  392.  
  393. // update the leader board when necessary:
  394. void leaders(int i, int* order)
  395. {
  396.    char string[] = "0123456789";
  397.    double Y;
  398.  
  399.    Y = LDR_BRD_Y - spacing * (i + 1);
  400.  
  401.    // Erase old text:
  402.    set_fill_color(FIELD_COLOR);             // The infield color
  403.    rectangle(LDR_BRD_X, Y, LDR_BRD_X+19*CHR_WID, Y - CHR_HGT);
  404.  
  405.    set_color(TEXT_COLOR);
  406.    text_output(LDR_BRD_X, Y, drivers[order[i]].rob_name);
  407.    get_max_spd(order[i], string);                    // the maximum speed:
  408.    text_output(LDR_BRD_X+7.5*CHR_WID, Y, string);
  409.    get_avg_spd(order[i], string);                    // the average speed:
  410.    text_output(LDR_BRD_X+13.5*CHR_WID, Y, string);
  411.    drawcar(LDR_BRD_X-1.2*CARLEN, Y - CARWID/2, 0.0,
  412.           drivers[order[i]].paint_job.nose, drivers[order[i]].paint_job.tail);
  413. }
  414.  
  415. void instruments(int i)   // Instrument Panel for car i
  416. {
  417.    char out[16];
  418.    static int alpha_up = 0;        // set when the descriptions are printed
  419.  
  420.    set_fill_color(FIELD_COLOR);             // The infield color
  421.    rectangle(IP_X, IP_Y, IP_X + 21 * CHR_WID, IP_Y - CHR_HGT); // erase name
  422.  
  423.    if(i < 0 || i >= car_count)  {   // Do nothing if i is invalid.
  424.       alpha_up = 0;
  425.       return;
  426.    }
  427.  
  428.    if(!alpha_up) {
  429.       set_color(TEXT_COLOR);
  430.       text_output(IP_X, IP_Y - CHR_HGT, "speedometer");
  431.       text_output(IP_X, IP_Y - 2 * CHR_HGT, "true speed");
  432.       text_output(IP_X, IP_Y - 3 * CHR_HGT, "lateral g's");
  433.       text_output(IP_X, IP_Y - 4 * CHR_HGT, "in-line g's");
  434.       text_output(IP_X, IP_Y - 5 * CHR_HGT, "skid angle");
  435.       text_output(IP_X, IP_Y - 6 * CHR_HGT, "power, pct.");
  436.       alpha_up = 1;
  437.    }
  438.  
  439.    set_color(IP_NAME_COLOR);
  440.    text_output(IP_X, IP_Y, drivers[i].rob_name);
  441.    text_output(IP_X + (strlen(drivers[i].rob_name)-.5) * CHR_WID, IP_Y, "'s instruments:");
  442.  
  443.    set_color(IP_NUM_COLOR);
  444.    rectangle(IP_X + 11 * CHR_WID, IP_Y - CHR_HGT,
  445.              IP_X + 17 * CHR_WID, IP_Y - 2 * CHR_HGT);
  446.    make_dec_string(out, pcar[i]->get_vc() * MPH_FPS);
  447.    text_output(IP_X + 11 * CHR_WID, IP_Y - CHR_HGT, out);
  448.  
  449.    rectangle(IP_X + 11 * CHR_WID, IP_Y - 2 * CHR_HGT,
  450.              IP_X + 17 * CHR_WID, IP_Y - 3 * CHR_HGT);
  451.    make_dec_string(out, pcar[i]->get_speed() * MPH_FPS);
  452.    text_output(IP_X + 11 * CHR_WID, IP_Y - 2 * CHR_HGT, out);
  453.  
  454.    rectangle(IP_X + 11 * CHR_WID, IP_Y - 3 * CHR_HGT,
  455.              IP_X + 17 * CHR_WID, IP_Y - 4 * CHR_HGT);
  456.    make_dec_string(out, pcar[i]->get_lat_acc());
  457.    text_output(IP_X + 11 * CHR_WID, IP_Y - 3 * CHR_HGT, out);
  458.  
  459.    rectangle(IP_X + 11 * CHR_WID, IP_Y - 4 * CHR_HGT,
  460.              IP_X + 17 * CHR_WID, IP_Y - 5 * CHR_HGT);
  461.    make_dec_string(out, pcar[i]->get_lin_acc());
  462.    text_output(IP_X + 11 * CHR_WID, IP_Y - 4 * CHR_HGT, out);
  463.  
  464.    rectangle(IP_X + 11 * CHR_WID, IP_Y - 5 * CHR_HGT,
  465.              IP_X + 17 * CHR_WID, IP_Y - 6 * CHR_HGT);
  466.    make_dec_string(out, pcar[i]->get_alpha() * DEGPRAD);
  467.    text_output(IP_X + 11 * CHR_WID, IP_Y - 5 * CHR_HGT, out);
  468.  
  469.    rectangle(IP_X + 11 * CHR_WID, IP_Y - 6 * CHR_HGT,
  470.              IP_X + 17 * CHR_WID, IP_Y - 7 * CHR_HGT);
  471.    make_dec_string(out, pcar[i]->get_power() * 100.0);
  472.    text_output(IP_X + 11 * CHR_WID, IP_Y - 6 * CHR_HGT, out);
  473. }
  474.  
  475. /* new routine: draw_arc() routine that uses draw_line() to draw the arc */ 
  476. #define LINESEG_LENGTH 07 /* this constant can be used to tweak the precision */
  477. void draw_arc(double radius, double center_x, double center_y, double start_angle, double length)
  478. {
  479.     double a;
  480.     double stepsize;
  481.     double x1, y1, x2, y2;
  482.  
  483.     /* convert a right turn so it is consistent with the left turn */
  484.     if (radius < 0.0)
  485.     {
  486.         radius = -radius;
  487.  
  488.         start_angle = start_angle - length - PI;
  489.         while (start_angle < 0.0)
  490.         {
  491.             start_angle += (2 * PI);
  492.         }
  493.     }
  494.  
  495.     /* calculate the starting point */
  496.     x1 = center_x + radius * sin(start_angle);
  497.     y1 = center_y - radius * cos(start_angle);
  498.  
  499.     /* determine the step size */
  500.     stepsize = LINESEG_LENGTH * (1.0 / (radius * SCALE));
  501.  
  502.     /* draw lines over the length from there, adapting the number of steps to the length */
  503.     for (a = stepsize; a < length; a += stepsize)
  504.     {
  505.         /* calculate the end point of this line */
  506.         x2 = center_x + radius * sin(start_angle + a);
  507.         y2 = center_y - radius * cos(start_angle + a);
  508.  
  509.         /* draw the line */
  510.         draw_line(x1, y1, x2, y2);
  511.  
  512.         /* make the end point the new starting point for the next line */
  513.         x1 = x2;
  514.         y1 = y2;
  515.     }
  516.  
  517.     /* calculate the end point of the arc */
  518.     x2 = center_x + radius * sin(start_angle + length);
  519.     y2 = center_y - radius * cos(start_angle + length);
  520.  
  521.     /* draw the last line */
  522.     draw_line(x1, y1, x2, y2);
  523. }
  524.  
  525.